package com.hoe.tsb.fraft;

import com.hoe.tsb.fraft.exception.FRaftException;

import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;

/**
 * <p>
 * LRU算法的集合
 * </p>
 *
 * @author hoe
 * @version 1.0
 * @date 2022/11/23 17:44
 */
public class LRUList<E> implements List<E> {

    private static class Node<E> {
        E data;
        Node<E> last;
        Node<E> next;
        Node(E data) {
            this.data = data;
        }
    }

    private int size = 0;
    private int capacity;
    private Node<E> first = null;
    private Node<E> finalize = null;

    public LRUList(int capacity) {
        if (capacity <= 0) {
            throw new FRaftException("容量不能小于0");
        }
        this.capacity = capacity;
    }

    @Override
    public int size() {
        return size;
    }

    @Override
    public boolean isEmpty() {
        return size == 0;
    }

    @Override
    public boolean contains(Object o) {
        Node<E> node = get(o);
        if (node != null) {
            //找到了就把该项放到最后
            swap(node, finalize);
            return true;
        }
        return false;
    }

    @Override
    public boolean add(E s) {
        if (size >= capacity) {
            //移除最前面的
            remove(first.data);
        }

        Node<E> node = get(s);
        if (node == null) {
            Node<E> newNode = new Node<E>(s);
            if (size == 0) {
                first = newNode;
            } else if (size == 1) {
                first.next = newNode;
                newNode.last = first;
            } else {
                finalize.next = newNode;
                newNode.last = finalize;
            }
            finalize = newNode;
            size++;
        } else {
            //将该元素换到最后
            swap(node, finalize);
        }

        return true;
    }

    @Override
    public boolean remove(Object o) {
        Node<E> node = get((String) o);
        if (node != null) {
            if (size == 1) {
                first = null;
                finalize = null;
            } else if (size == 2) {
                Node<E> another = node.last == null ? node.next : node.last;
                another.next = null;
                another.last = null;
                first = another;
                finalize = another;
            } else {
                //移除的是first
                if (node.last == null) {
                    first = node.next;
                    first.last = null;
                }
                //移除的是finalize
                else if (node.next == null) {
                    finalize = node.last;
                    finalize.next = null;
                }
                //移除的是中间
                else {
                    node.last.next = node.next;
                    node.next.last = node.last;
                }
            }
            size--;
            return true;
        }
        return false;
    }

    @Override
    public E set(int index, E element) {
        int idx = 0;

        //默认从头开始遍历，可以优化为双向遍历
        Node target = first;
        do {
            target = target.next;
        } while(idx++ < index && target != null);

        //相当于追加到末尾
        if (target == null) {
            add(element);
        } else {
            Node newNode = new Node(element);
            newNode.last = target.last;
            newNode.next = target;
            target.last = newNode;
            size++;
        }

        return element;
    }

    @Override
    public void add(int index, E element) {
        set(index, element);
    }

    @Override
    public E get(int index) {
        if (index >= size) {
            throw new FRaftException(index + " of " + size);
        }

        int i = 0;
        Node<E> target = first;
        while(i++ < index) {
            target = target.next;
        }

        return target.data;
    }

    @Override
    public Object[] toArray() {
        if (size == 0) {
            return new Object[0];
        } else {
            Object[] arr = new Object[size];
            int idx = 0;
            Node next = first;
            while(idx < size) {
                arr[idx] = next.data;
                next = next.next;
                idx++;
            }
            return arr;
        }
    }

    @Override
    public <T> T[] toArray(T[] a) {
        throw new FRaftException("暂不支持该方法");
    }

    @Override
    public E remove(int index) {
        throw new FRaftException("暂不支持该方法");
    }

    @Override
    public int indexOf(Object o) {
        throw new FRaftException("暂不支持该方法");
    }

    @Override
    public void clear() {
        throw new FRaftException("暂不支持该方法");
    }

    @Override
    public boolean containsAll(Collection<?> c) {
        throw new FRaftException("暂不支持该方法");
    }

    @Override
    public boolean addAll(Collection<? extends E> c) {
        throw new FRaftException("暂不支持该方法");
    }

    @Override
    public boolean addAll(int index, Collection<? extends E> c) {
        throw new FRaftException("暂不支持该方法");
    }

    @Override
    public boolean removeAll(Collection<?> c) {
        throw new FRaftException("暂不支持该方法");
    }

    @Override
    public boolean retainAll(Collection<?> c) {
        throw new FRaftException("暂不支持该方法");
    }

    @Override
    public int lastIndexOf(Object o) {
        throw new FRaftException("暂不支持该方法");
    }

    @Override
    public ListIterator<E> listIterator() {
        throw new FRaftException("暂不支持该方法");
    }

    @Override
    public ListIterator<E> listIterator(int index) {
        throw new FRaftException("暂不支持该方法");
    }

    @Override
    public List<E> subList(int fromIndex, int toIndex) {
        throw new FRaftException("暂不支持该方法");
    }

    @Override
    public Iterator<E> iterator() {
        throw new FRaftException("暂不支持该方法");
    }

    /**
     * 交换对象
     *
     * @param a 待交换元素a
     * @param b 待交换元素b
     */
    private void swap(Node<E> a, Node<E> b) {
        //直接交换内容
        E tmp = a.data;
        a.data = b.data;
        b.data = tmp;
    }

    private Node<E> get(Object ele) {
        if (first != null) {
            Node<E> next = first;
            do {
                if (next.data != null && next.data.equals(ele)) {
                    return next;
                }
                next = next.next;
            } while (next != null);
        }
        return null;
    }
}
